package com.example.customview.view

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.ViewConfiguration
import android.view.ViewGroup
import android.widget.OverScroller
import androidx.core.view.children
import kotlin.math.abs

/**
 * 横向滑动的 ViewPager
 */
class TwoPager(context: Context, attrs: AttributeSet) : ViewGroup(context, attrs) {

    private val overScroller = OverScroller(context)
    private val velocityTracker = VelocityTracker.obtain()
    private val viewConfiguration = ViewConfiguration.get(context)

    // 滑动的阈值
    private val pagingSlop = viewConfiguration.scaledPagingTouchSlop

    // 最小的快滑速度
    private val minVelocity = viewConfiguration.scaledMinimumFlingVelocity

    // 最大的快滑速度
    private val maxVelocity = viewConfiguration.scaledMaximumFlingVelocity

    private var scrolling = false

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        /**
         * 给所有子 View  一个统一的宽高限制，所有子 View 一样宽 一样高
         */
        measureChildren(widthMeasureSpec, heightMeasureSpec)
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        // 从左上角开始拜访，然后往右移
        var childLeft = 0
        val childTop = 0
        var childRight = width
        val childBottom = height
        for (child in children) {
            child.layout(childLeft, childTop, childRight, childBottom)
            childLeft += width
            childRight += width
        }

    }

    private var downX = 0f
    private var downY = 0f
    private var downScrollX = 0f

    /**
     * ① 做初始状态记录
     * ② 做状态拦截
     */
    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        if (ev.actionMasked == MotionEvent.ACTION_DOWN) {
            velocityTracker.clear()
        }
        velocityTracker.addMovement(ev)

        var result = false
        when (ev.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                scrolling = false
                /**
                 * 这里也要记录一下按下的初始位置，方便后面拦截之后需要用到这些值
                 * 在可滑动控件中，用户可能是按着某个子 View 滑动
                 *              {   1.这种情况下
                 *                  第一个down 事件，子 View 的 onTouchEvent 能收到
                 *                  但是父 View 收不到，但是父 View 的 onInterceptTouchEvent 能收到
                 *              }
                 *
                 *              也可能是按着外层的滑动控件滑动
                 *              {   2.这种情况下，
                 *                  子 View 全程收不到任何事件，而父 View 可以收到每一个事件
                 *              }
                 *      当时第一中情况，父 View 之后进行滑动拦截的操作时，
                 *      就需要在 onInterceptTouchEvent 中记录下当时落下的点的坐标了
                 */
                downX = ev.x
                downY = ev.y
                downScrollX = scrollX.toFloat()
            }
            MotionEvent.ACTION_MOVE -> {
                if (!scrolling) {
                    val dx = downX - ev.x // 滑动的距离
                    if (abs(dx) > pagingSlop) { // 如果滑动的距离足够长
                        scrolling = true
                        // 通知父 View 不要拦截自己了
                        parent.requestDisallowInterceptTouchEvent(true)
                        result = true // 返回 true 表示自己要拦截了，让子 View 去 cancel
                    }
                }

            }
        }
        return result
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        // 重置
        if (event.actionMasked == MotionEvent.ACTION_DOWN) {
            velocityTracker.clear()
        }
        // 把所有事件都交给它
        velocityTracker.addMovement(event)
        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                downX = event.x
                downY = event.y
                downScrollX = scrollX.toFloat()
            }
            MotionEvent.ACTION_MOVE -> {
                /**
                 * 偏移计算
                 * 注意这里是用  落下点减去当前点
                 * 因为 scrollTo 的模型是反的
                 */
                val dx = (downX - event.x + downScrollX).toInt()
                    .coerceAtLeast(0)
                    .coerceAtMost(width)
                scrollTo(dx, 0)
            }
            MotionEvent.ACTION_UP -> {
                /**
                 * 用来在做惯性滑动的时候计算初始速度
                 * 1000ms 移动的像素数
                 */
                velocityTracker.computeCurrentVelocity(1000, maxVelocity.toFloat())
                // x 方向的速度值
                val vx = velocityTracker.xVelocity

                val scrollX = scrollX
                var targetPage = 0// 目标停靠页
                // 判断往哪边停靠
                if (abs(vx) < minVelocity) {// 手指的滑动速度比较小
                    targetPage = if (scrollX > width / 2) 1 else 0
                } else { // 快滑 负值表示你往负向快滑，往左
                    targetPage = if (vx < 0) 1 else 0
                }
                val scrollDistance = if (targetPage == 1) width - scrollX else -scrollX
                /**
                 *给你一个目标位置，你自己计算怎么移动过去
                 */
                overScroller.startScroll(getScrollX(), 0, scrollDistance, 0)
                /**
                 * 更新界面
                 * 在下一帧将我的页面标记为失效，需要配合重写 computeScroll()
                 * 标记失效之后，draw() 方法会被调用，
                 * draw() 内部会调用 computeScroll()
                 */
                postInvalidateOnAnimation()

            }
        }

        return true
    }

    override fun computeScroll() {
        if (overScroller.computeScrollOffset()) {
            scrollTo(overScroller.currX, overScroller.currY)
            postInvalidateOnAnimation()
        }

    }
}